//********************************************************************************************************
// Product Name: MapWindow.dll Alpha
// Description:  The basic module for MapWindow version 6.0
//********************************************************************************************************
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at 
// http://www.mozilla.org/MPL/ 
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 
// ANY KIND, either expressed or implied. See the License for the specificlanguage governing rights and 
// limitations under the License. 
//
// The Original Code is from MapWindow.dll version 6.0
//
// The Initial Developer of this Original Code is Ted Dunsford. Created 6/9/2008 12:35:06 PM
// 
// Contributor(s): (Open source contributors should list themselves and their modifications here). 
//
//********************************************************************************************************

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;


namespace MapWindow.DirectX
{


    /// <summary>
    /// TextureComponent
    /// </summary>
    public class TextureComponent : IDrawingComponent
    {

      

        #region Events

        /// <summary>
        /// Occurs after the device is initialized during a drawing cycle.
        /// </summary>
        public event EventHandler Initialized;

        /// <summary>
        /// Occurs when the Invalidate method is called
        /// </summary>
        public event EventHandler Invalidated;

        #endregion

        #region Private Variables

        private Texture _texture;
        private string _filename;
        private bool _isInitialized;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new instance of TextureComponent
        /// </summary>
        public TextureComponent(string filename)
        {
            _filename = filename;
        }

        /// <summary>
        ///  Creates a new instante of the TextureComponent without specifying a filename
        /// </summary>
        public TextureComponent()
        {
           
        }

        #endregion

        #region Methods

        /// <summary>
        /// This method should be called after the drawing has taken place.
        /// </summary>
        /// <param name="device"></param>
        public virtual void AfterDrawing(Device device)
        {
            device.SetTexture(0, null);
            DisableTransparency(device);
        }


        /// <summary>
        /// This doesn't physically draw the indicies, but simply sets the index buffer.
        /// If the index buffer hasn't yet been initialized, this will take care of that.
        /// </summary>
        /// <param name="device"></param>
        public virtual void BeforeDrawing(Device device)
        {
            if (_isInitialized == false)
            {
                Load(device, _filename);
            }
            EnableTransparency(device);
            device.SetTexture(0, _texture);
        }

        /// <summary>
        /// Disposes any unmanaged memory objects.  This will not affect the managed
        /// variables.
        /// </summary>
        public virtual void Dispose()
        {
            if(_texture != null)_texture.Dispose();
        }


        /// <summary>
        /// Generates a new texture using the specified image.
        /// </summary>
        /// <param name="device">The Graphics device to specify what type of texture should be created.</param>
        /// <param name="image">A System.Drawing.Drawing2D Image object to create a texture from.</param>
        void FromBitmap(Device device, Bitmap image)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// This invalidates the drawing component so that it has to be re-initialized
        /// during the next drawing cycle
        /// </summary>
        public virtual void Invalidate()
        {
            _isInitialized = false;
            OnInvalidated(this, new EventArgs());
        }


       

        /// <summary>
        /// Instructs the texture to load from the file.
        /// </summary>
        /// <param name="device">The Device to use to load the value.  This should match the form of the graphics object used.</param>
        /// <param name="filename">The string filename of the actual file to load</param>
        public virtual void Load(Device device, string filename)
        {
            _texture = TextureLoader.FromFile(device, filename);
        }

        /// <summary>
        /// Converts the texture memory object from its native format into an image
        /// </summary>
        /// <returns>A System.Drawing.Image that should be converted into a texture</returns>
        public virtual Image ToImage()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Saves the file using the specified filename.  The image format will be determined from the filename.
        /// </summary>
        /// <param name="filename">The string filename.</param>
        public virtual void Save(string filename)
        {
            string ext = System.IO.Path.GetExtension(filename);
            ImageFileFormat format = ImageFileFormat.Bmp;
            ext = ext.ToLower();
            switch (ext)
            {
                case ".bmp":format = ImageFileFormat.Bmp; break;
                case ".dds": format = ImageFileFormat.Dds; break;
                case ".dib": format = ImageFileFormat.Dib; break;
                case ".hdr": format = ImageFileFormat.Hdr; break;
                case ".jpg":format = ImageFileFormat.Jpg; break;
                case ".pfm":format = ImageFileFormat.Pfm; break;
                case ".png":format = ImageFileFormat.Png; break;
                case ".ppm":format = ImageFileFormat.Ppm; break;
                case ".tga":format = ImageFileFormat.Tga; break;
            }
            TextureLoader.Save(filename, format, _texture);
        }


        /// <summary>
        /// Saves the texture using the current filename, determining the image format from the extension.
        /// </summary>
        public virtual void Save()
        {
            Save(_filename);
        }


        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets a string filename where this texture is found on the disk.
        /// </summary>
        public virtual string Filename
        {
            get { return _filename; }
            set { _filename = value; }
        }

        /// <summary>
        /// Gets a boolean value indicating whether or not this drawing component has
        /// been initialized
        /// </summary>
        public virtual bool IsInitialized
        {
            get { return _isInitialized; }
            protected set { _isInitialized = value; }
        }

        /// <summary>
        /// Gets or sets the Texture
        /// </summary>
        public Texture TextureDX
        {
            get { return _texture; }
            set 
            {
                if (_texture != null) _texture.Dispose();
                _texture = value;
                _isInitialized = true; // Setting this assumes that we are good to go and won't load from a file.
            }
        }

        private void EnableTransparency(Device device)
        {
            device.RenderState.SourceBlend = Blend.SourceAlpha;
            device.RenderState.DestinationBlend = Blend.InvSourceAlpha;
            device.RenderState.AlphaBlendEnable = true;
            device.TextureState[0].ColorOperation = TextureOperation.Modulate;
            device.TextureState[0].ColorArgument0 = TextureArgument.Diffuse;
            device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
            device.TextureState[0].AlphaOperation = TextureOperation.Modulate;
            device.TextureState[0].AlphaArgument0 = TextureArgument.Diffuse;
            device.TextureState[0].AlphaArgument1 = TextureArgument.TextureColor;
        }

        private void DisableTransparency(Device device)
        {
            // turn off the transparent texture handling
            device.RenderState.AlphaBlendEnable = false;

            // Not sure if this does anything useful
            device.RenderState.SourceBlend = Blend.One;
            device.RenderState.DestinationBlend = Blend.Zero;
        }


        #endregion

        #region Protected Methods

        /// <summary>
        /// Fires the Invalidated Event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnInvalidated(object sender, EventArgs e)
        {
            if (Invalidated != null)
            {
                Invalidated(sender, e);
            }
        }

        /// <summary>
        /// Fires the Initialized Event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnInitialized(object sender, EventArgs e)
        {
            if (Initialized != null)
            {
                Initialized(sender, e);
            }
        }

        #endregion


    }
}
